/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.escom.healthlc.business;

import com.escom.healthlc.utils.Constantes;
import com.escom.healthlc.utils.PropiedadesMemoria;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 *
 * @author Carlos
 */
@Service("EcgBusiness")
public class EcgBusiness {

    private static final Logger logger = LoggerFactory.getLogger(EcgBusiness.class);
    private static final int TAMANIO_PROMEDIO_PATRON = 60;
    private List<String> coordenadas;
    
//    public static void main(String[] args) throws FileNotFoundException, IOException {
//        EcgBusiness ecgBusiness = new EcgBusiness();
//        List<Double> crearListValues = ecgBusiness.crearListValues(new FileInputStream(new File("C:\\Users\\Carlos\\Dropbox\\Trabajo Terminal\\Señal\\ECG_taquicardia.txt")));
//        double[][] segmentarSenial = ecgBusiness.segmentarSenial(crearListValues, 3.6);
//        for (int i = 0; i < segmentarSenial.length; i++) {
//            for (int j = 0; j < segmentarSenial[i].length; j++) {
//                System.out.print(segmentarSenial[i][j] + "\t");
//            }
//            System.out.println("");
//        }
//        ecgBusiness.crearMemoriaAsocitiva();
//        ecgBusiness.recuperarPatron();
//    }

    public List<Double> crearListValues(InputStream inputstream) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputstream));
        List<Double> valuesECG = new ArrayList();
        while (bufferedReader.ready()) {
            String readLine = bufferedReader.readLine();
//            String[] lineSplit = readLine.split(",");
//            for (int i = 0; i < lineSplit.length; i++) {
                valuesECG.add(Double.valueOf(readLine));
//            }
        }
        return valuesECG;
    }

    public double[][] segmentarSenial(List<Double> senialList, double lineDelimiter) {
        coordenadas = new ArrayList<String>();
        /*Calcula puntos maximos*/
        List<Integer> xPtMaximo = new ArrayList<Integer>();
        for (int i = 0; i < senialList.size(); i++) {
            Double value = senialList.get(i);
            if (value > lineDelimiter) {
                xPtMaximo.add(i);
            }
        }
        /*Calcular en base dos Pts maximos el punto medio de la señal*/
        List<Integer> xPtMedio = new ArrayList<Integer>();
        List<Integer> tamanioPatron = new ArrayList<Integer>();
        for (int i = 0; i < xPtMaximo.size() - 1; i++) {
            xPtMedio.add(((xPtMaximo.get(i + 1) - xPtMaximo.get(i)) / 2) + xPtMaximo.get(i));
            tamanioPatron.add(xPtMaximo.get(i + 1) - xPtMaximo.get(i));
        }
        xPtMedio.add(senialList.size() - 1);

        /*Obtener segmentos del patron*/
        double[][] patrones = new double[xPtMedio.size()][TAMANIO_PROMEDIO_PATRON];//NOTA FALTA
        for (int i = 0; i < xPtMedio.size(); i++) {
            /*Segmentos de la señal en base al inico hasta el punto medio ITERATIVO*/
            coordenadas.add(((i > 0) ? xPtMedio.get(i - 1) : 0) + "," + xPtMedio.get(i));
            List<Double> segmentoSenial = senialList.subList((i > 0) ? xPtMedio.get(i - 1) : 0, xPtMedio.get(i));
            List<Double> copySegmento = null;
            //Interpolacion y Diezmado
            while (segmentoSenial.size() != 60) {
                int sizeSegmentoSenial = segmentoSenial.size();
                if (sizeSegmentoSenial < TAMANIO_PROMEDIO_PATRON) {
                    copySegmento = funcionInterpolacion(segmentoSenial);
                } else if (sizeSegmentoSenial > TAMANIO_PROMEDIO_PATRON) {
                    copySegmento = funcionDiezmado(segmentoSenial);
                }
                segmentoSenial = copySegmento;
            }
//            System.out.println("segmentoSenial: " + segmentoSenial.size());
            for (int k = 0; k < segmentoSenial.size(); k++) {
                patrones[i][k] = segmentoSenial.get(k);
            }

        }
        return patrones;
    }

    public List<Double> funcionDiezmado(List<Double> patron) {
        int sizePatron = patron.size();
        List<Double> copiPatron = new ArrayList<Double>();
        int muestrasSobrantes = sizePatron - TAMANIO_PROMEDIO_PATRON;
        int factorDiezmado = (int) Math.floor(sizePatron / muestrasSobrantes);
        if (factorDiezmado >= sizePatron) {
            factorDiezmado--;
        }
        for (int i = 0; i < patron.size(); i++) {
            if (i == 0 || (i % factorDiezmado) != 0) {
                copiPatron.add(patron.get(i));
            }
        }
        return copiPatron;
    }

    public List<Double> funcionInterpolacion(List<Double> patron) {
        List<Double> copiPatron = new ArrayList<Double>();
        int sizePatron = patron.size();
        int muestrasFaltantes = TAMANIO_PROMEDIO_PATRON - sizePatron;
        int factorInterpolacion = (int) Math.rint(sizePatron / muestrasFaltantes);
        if (factorInterpolacion >= sizePatron) {
            factorInterpolacion--;
        }
        int j = 0;
        if (factorInterpolacion > 1) {
//            System.out.println("Caso 1");
            for (int i = 0; j < patron.size(); i++) {
                if ((i % factorInterpolacion) != 0) {
                    copiPatron.add(patron.get(j));
                    j++;
                } else {
                    if ((j - 1) < 0) {
                        copiPatron.add(patron.get(j));
                        j++;
                    } else {
                        Double bottom = patron.get(j - 1);
                        Double top = patron.get(j);
                        copiPatron.add(Math.abs((top + bottom) / 2));
                    }
                }
            }
        } else if (factorInterpolacion <= 1) {
//            System.out.println("Caso 2");
            muestrasFaltantes = (int) Math.rint((TAMANIO_PROMEDIO_PATRON / sizePatron));
            int i = 0;
            while (j + 1 < patron.size()) {
                Double bottom = patron.get(j);
                Double top = patron.get(j + 1);
                double valorResta = Math.abs(top - bottom);
                double factorInterpolacionDouble = valorResta / (muestrasFaltantes);
                if (top > bottom) {
                    copiPatron.add(bottom);
                    for (int k = 0; k < muestrasFaltantes - 1; k++) {
                        copiPatron.add(bottom + (factorInterpolacionDouble * (k + 1)));
                    }
                } else {
                    copiPatron.add(bottom);
                    for (int k = 0; k < muestrasFaltantes - 1; k++) {
                        copiPatron.add(bottom - (factorInterpolacionDouble * (k + 1)));
                    }
                }
                j++;
            }
        }
//        System.out.println("copiPatron.size(): " + copiPatron.size());
        return copiPatron;
    }

    public void salvarSegmentos(double[][] segmentosSenial, int[] opcTipoArritmiaArray) {
        try {
            PrintWriter printWriter = new PrintWriter(new FileWriter(new File(Constantes.PATH_WEB_VIRTUAL) + "\\PatronesECG.txt", true));
            String line;
            for (int i = 0; i < segmentosSenial.length; i++) {
                line = "";
                for (int j = 0; j < segmentosSenial[i].length; j++) {
                    line += segmentosSenial[i][j] + " ";
                }
                line += opcTipoArritmiaArray[i];
                printWriter.println(line);
            }
            printWriter.close();
        } catch (IOException ex) {
            logger.error("Error Logger: {}", ex.getCause().getMessage());
            logger.error("Error Logger: {}", ex.fillInStackTrace().toString());
        }
    }

    public void crearMemoriaAsocitiva() {
        try {
            PropiedadesMemoria propiedadesMemoria;
            double[] vectorMedio;
            double[][] patronesAllMatriz;
            double[][] patronesTrasladoAllMatriz;
            double[][] memoriaMatriz;
            File fileRouthIn, fileRouthPatronesTrasladados, fileRouthMemoria, fileRouthVectorMedio;
            fileRouthIn = new File(Constantes.PATH_WEB_VIRTUAL + "\\PatronesECG.txt");
            fileRouthPatronesTrasladados = new File(Constantes.PATH_WEB_VIRTUAL + "\\PatronesTrasladados.txt");
            fileRouthMemoria = new File(Constantes.PATH_WEB_VIRTUAL + "\\Memoria.txt");
            fileRouthVectorMedio = new File(Constantes.PATH_WEB_VIRTUAL + "\\VectorMedio.txt");
            propiedadesMemoria = new PropiedadesMemoria();

            propiedadesMemoria.DataInit(new BufferedReader(new FileReader(fileRouthIn)));
            patronesAllMatriz = propiedadesMemoria.ExtraccionPatrones(new BufferedReader(new FileReader(fileRouthIn)));

            vectorMedio = propiedadesMemoria.CalcularVectorMedio(patronesAllMatriz);
            propiedadesMemoria.EscribirArreglo(vectorMedio, new BufferedWriter(new FileWriter(fileRouthVectorMedio)));

            patronesTrasladoAllMatriz = propiedadesMemoria.CalcularPatronesTrasladados(patronesAllMatriz, vectorMedio);
            propiedadesMemoria.EscribirMatriz(patronesTrasladoAllMatriz, new BufferedWriter(new FileWriter(fileRouthPatronesTrasladados)));

            memoriaMatriz = propiedadesMemoria.CalcularMemoria(patronesTrasladoAllMatriz);
            propiedadesMemoria.EscribirMatriz(memoriaMatriz, new BufferedWriter(new FileWriter(fileRouthMemoria)));

            propiedadesMemoria.RecuperacionData(patronesTrasladoAllMatriz, memoriaMatriz);

            System.out.println(propiedadesMemoria.getEficienciaTotal() + "");
        } catch (IOException ex) {
            java.util.logging.Logger.getLogger(EcgBusiness.class.getName()).log(Level.SEVERE, null, ex);
//            logger.error("Error Logger: {}", ex.getCause().getMessage());
//            logger.error("Error Logger: {}", ex.fillInStackTrace().toString());
        }
    }

//    public void recuperarPatron(double[][] patronesAllMatriz) {
    public List<String> recuperarPatron(double[][] patronesAllMatriz) {
        List<String> clasificarPatrones = new ArrayList<String>();
        try {
            PropiedadesMemoria propiedadesMemoria;
            double[] vectorMedio;
//            double[][] patronesAllMatriz;
            double[][] patronesTrasladoAllMatriz;
            double[][] memoriaMatriz;
            File fileRouthIn, fileRouthPatronesTrasladados, fileRouthMemoria, fileRouthVectorMedio;
            fileRouthIn = new File(Constantes.PATH_WEB_VIRTUAL + "\\PatronesECGSinEtiqueta.txt");
            fileRouthPatronesTrasladados = new File(Constantes.PATH_WEB_VIRTUAL + "\\PatronesTrasladados.txt");
            fileRouthMemoria = new File(Constantes.PATH_WEB_VIRTUAL + "\\Memoria.txt");
            fileRouthVectorMedio = new File(Constantes.PATH_WEB_VIRTUAL + "\\VectorMedio.txt");
            propiedadesMemoria = new PropiedadesMemoria();

//            propiedadesMemoria.DataInit(new BufferedReader(new FileReader(fileRouthIn)));
            propiedadesMemoria.setNoPatronesTotal(patronesAllMatriz.length);
//            propiedadesMemoria.setNoClases(5);
            propiedadesMemoria.setNoElementosPorPatron(60);
//            patronesAllMatriz = propiedadesMemoria.ExtraccionPatrones(new BufferedReader(new FileReader(fileRouthIn)));

            vectorMedio = propiedadesMemoria.LeerVectorMedio(new BufferedReader(new FileReader(fileRouthVectorMedio)));

            patronesTrasladoAllMatriz = propiedadesMemoria.CalcularPatronesTrasladados(patronesAllMatriz, vectorMedio);

            memoriaMatriz = propiedadesMemoria.LeerMemoria(new BufferedReader(new FileReader(fileRouthMemoria)));
            clasificarPatrones = propiedadesMemoria.ClasificarPatrones(patronesTrasladoAllMatriz, memoriaMatriz);

            System.out.println(propiedadesMemoria.getEficienciaTotal() + "");

        } catch (IOException ex) {
            java.util.logging.Logger.getLogger(EcgBusiness.class.getName()).log(Level.SEVERE, null, ex);

//            logger.error("Error Logger: {}", ex.getCause().getMessage());
//            logger.error("Error Logger: {}", ex.fillInStackTrace().toString());
        }
        return clasificarPatrones;

    }

    public List<String> getCoordenadas() {
        return coordenadas;
    }

}
